#include <gpdr.h>
#include <delay.h>
#include <stdio.h>
#include <string.h>
#include <nmea.h>

#define RTC_TIME_CHECK_WINDOW_START 30
#define RTC_TIME_CHECK_WINDOW_END 38
#define RTC_TIME_CHECK_MAX_DIFF 1

extern volatile unsigned char full_messages;
//extern unsigned char write_stat;

unsigned char gps_gets(char *str, unsigned char len, char delim)
{
unsigned char n = len;
char *p = str;
char k;

while (n)
      {
      l0:
      k = gps_getchar();
//      k=gps_getchar_timed(10);
      if (k == 8)
         {
         if (len > n)
            {
            --p;
            ++n;
            };
         goto l0;
         };
//      if (k==0) break;
//      if ((k == 0) || (k == delim) || (k = -1)) break;
      if ((k == 0) || (k == delim)) break;
      *p++ = k;
      --n;
      };
*p=0;
return (len - n);
}

void nmea_read(gpgga_struct *gpgga_msg, gprmc_struct *gprmc_msg, unsigned char mode) // mode 1 displays message
{
unsigned char temp[40];
//unsigned char gpgga_disp[90], rtc_sec;

(*gpgga_msg).NS = 83;
(*gpgga_msg).EW = 69;

if (full_messages == 1) // DEBUG code to be removed later
    {
    strf2buffer("Debug:");
    char2buffer(gps_gets(temp, 8, 10) + 48);
    char2buffer(strncmpf(temp, "$GPGGA", 6) + 48);
    char2buffer(strncmpf(temp, "$GPRMC", 6) + 48);
    str2buffer(temp);
    strf2buffer("\r");
    }
    
if (strncmpf(temp, "$GPGGA", 6) == 0)
    {
    if (full_messages == 1)
        {
        strf2buffer("Decoding GPGGA\r");
        }
        
    rtc_read((*gpgga_msg).rtc_msg);
    
    sscanf(temp, "%s", (*gpgga_msg).header); // $GPGGA

    gps_gets(temp, 13, 10);
    if (temp[0])
        {
        sscanf(temp, "%02u%02u%02u.%u", &(*gpgga_msg).hh, &(*gpgga_msg).mm, &(*gpgga_msg).ss, &(*gpgga_msg).ms); // hhmmss.sss
        sscanf(temp, "%02x%02x%02x.%u", &(*gpgga_msg).xhh, &(*gpgga_msg).xmm, &(*gpgga_msg).xss, &(*gpgga_msg).ms); // hhmmss.sss
        }
        
    gps_gets(temp, 11, 10);
    if (temp[0]) sscanf(temp, "%02u%02u.%u", &(*gpgga_msg).latdd, &(*gpgga_msg).latmm, &(*gpgga_msg).latdmm); // ddmm.mmmm
    gps_gets(temp, 3, 10);
    if (temp[0]) sscanf(temp, "%c", &(*gpgga_msg).NS); // N or S
    gps_gets(temp, 12, 10);
    if (temp[0]) sscanf(temp, "%03u%02u.%u", &(*gpgga_msg).londd, &(*gpgga_msg).lonmm, &(*gpgga_msg).londmm); // dddmm.mmmm
    gps_gets(temp, 3, 10);
    if (temp[0]) sscanf(temp, "%c", &(*gpgga_msg).EW); // E or W
    gps_gets(temp, 3, 10);
    if (temp[0]) sscanf(temp, "%u", &(*gpgga_msg).qual); // quality
    gps_gets(temp, 4, 10);
    if (temp[0]) sscanf(temp, "%02u", &(*gpgga_msg).SVs); // SVs
    gps_gets(temp, 6, 10);
    if (temp[0]) sscanf(temp, "%2u.%u", &(*gpgga_msg).hdop, &(*gpgga_msg).dhdop); // xx.x
    gps_gets(temp, 10, 10);
    if (temp[0]) sscanf(temp, "%i.%u", &(*gpgga_msg).alt, &(*gpgga_msg).dalt); // Altitude +xxxxx.x
    gps_gets(temp, 3, 10);
    if (temp[0]) sscanf(temp, "%c", &(*gpgga_msg).alt_units); // M
    gps_gets(temp, 10, 10);
    if (temp[0]) sscanf(temp, "%i.%u", &(*gpgga_msg).geoid, &(*gpgga_msg).dgeoid); // Geoidal Separation +xxxxx.x
    gps_gets(temp, 3, 10);
    if (temp[0]) sscanf(temp, "%c", &(*gpgga_msg).geoid_units); // M
    gps_gets(temp, 6, 10);
    if (temp[0]) sscanf(temp, "%u", &(*gpgga_msg).base); // DGPS base ID
    gps_gets(temp, 6, 10);
    if (temp[0]) sscanf(temp, "*%x", &(*gpgga_msg).checksum); // checksum
//    scanf("%s", temp); // drain stream, should be null
//    write_stat = write_stat + strlen(temp);

    if (mode&0x01)
        {
        sprintf(temp, "GPGGA:%02u%02u%02u.%03u,", (*gpgga_msg).hh, (*gpgga_msg).mm, (*gpgga_msg).ss, (*gpgga_msg).ms);
        str2buffer(temp);
        sprintf(temp, "%02u%02u.%04u,%c,%03u%02u.%04u,%c,", (*gpgga_msg).latdd, (*gpgga_msg).latmm, (*gpgga_msg).latdmm, (*gpgga_msg).NS, (*gpgga_msg).londd, (*gpgga_msg).lonmm, (*gpgga_msg).londmm, (*gpgga_msg).EW);
        str2buffer(temp);
        sprintf(temp, "%u,%i.%01u,%c\r", (*gpgga_msg).SVs, (*gpgga_msg).alt, (*gpgga_msg).dalt, (*gpgga_msg).alt_units);
        str2buffer(temp);
        }   
    }

else if (strncmpf(temp, "$GPRMC", 6) == 0)
    {
    if (full_messages == 1)
        {
        strf2buffer("Decoding GPRMC\r");
        }
        
    rtc_read((*gprmc_msg).rtc_msg);
    
    sscanf(temp, "%s", (*gprmc_msg).header); // $GPRMC

    gps_gets(temp, 13, 10);
    if (temp[0])
        {
        sscanf(temp, "%02u%02u%02u.%u", &(*gprmc_msg).hh, &(*gprmc_msg).mm, &(*gprmc_msg).ss, &(*gprmc_msg).ms); // hhmmss.sss
        sscanf(temp, "%02x%02x%02x.%u", &(*gprmc_msg).xhh, &(*gprmc_msg).xmm, &(*gprmc_msg).xss, &(*gprmc_msg).ms); // hhmmss.sss
        }

    gps_gets(temp, 3, 10);
    if (temp[0]) sscanf(temp, "%c", &(*gprmc_msg).stat); // A or V
    gps_gets(temp, 11, 10);
    if (temp[0]) sscanf(temp, "%02u%02u.%u", &(*gprmc_msg).latdd, &(*gprmc_msg).latmm, &(*gprmc_msg).latdmm); // ddmm.mmmm
    gps_gets(temp, 3, 10);
    if (temp[0]) sscanf(temp, "%c", &(*gprmc_msg).NS); // N or S
    gps_gets(temp, 12, 10);
    if (temp[0]) sscanf(temp, "%03u%02u.%u", &(*gprmc_msg).londd, &(*gprmc_msg).lonmm, &(*gprmc_msg).londmm); // dddmm.mmmm
    gps_gets(temp, 3, 10);
    if (temp[0]) sscanf(temp, "%c", &(*gprmc_msg).EW); // E or W
    gps_gets(temp, 10, 10);
    if (temp[0]) sscanf(temp, "%i.%u", &(*gprmc_msg).speed, &(*gprmc_msg).dspeed); // Speed +xxxxx.x
    gps_gets(temp, 8, 10);
    if (temp[0]) sscanf(temp, "%i.%u", &(*gprmc_msg).course, &(*gprmc_msg).dcourse); // Course +xxx.xx
    gps_gets(temp, 8, 10);
    if (temp[0]) sscanf(temp, "%02u%02u%02u", &(*gprmc_msg).DD, &(*gprmc_msg).MM, &(*gprmc_msg).YY); // DDMMYY
    gps_gets(temp, 7, 10);
    if (temp[0]) sscanf(temp, "%u.%u", &(*gprmc_msg).mvar, &(*gprmc_msg).dmvar); // x.xx
    gps_gets(temp, 3, 10);
    if (temp[0]) sscanf(temp, "%c", &(*gprmc_msg).mvarEW); // E or W
    gps_gets(temp, 3, 10);
    if (temp[0]) sscanf(temp, "%c", &(*gprmc_msg).mode); // A, D, or E
    gps_gets(temp, 6, 10);
    if (temp[0]) sscanf(temp, "*%x", &(*gpgga_msg).checksum); // checksum
//    scanf("%s", temp); // drain stream, should be null
//    write_stat = write_stat + strlen(temp);

    if (mode&0x01)
        {
        sprintf(temp, "GPRMC:%02u%02u%02u.%03u,", (*gprmc_msg).hh, (*gprmc_msg).mm, (*gprmc_msg).ss, (*gprmc_msg).ms);
        str2buffer(temp);
        sprintf(temp, "%02u%02u.%04u,%c,%03u%02u.%04u,%c,", (*gprmc_msg).latdd, (*gprmc_msg).latmm, (*gprmc_msg).latdmm, (*gprmc_msg).NS, (*gprmc_msg).londd, (*gprmc_msg).lonmm, (*gprmc_msg).londmm, (*gprmc_msg).EW);
        str2buffer(temp);
        sprintf(temp, "%u.%01u,%u.%02u\r", (*gprmc_msg).speed, (*gprmc_msg).dspeed, (*gprmc_msg).course, (*gprmc_msg).dcourse);
        str2buffer(temp);
        }   
    }

else
    {
    do
        {
        } while (gps_gets(temp, 10, 0) == 10);
    }

//if ((mode&0x02) && ((*gpgga_msg).dss == 0) && ((*gpgga_msg).ss > RTC_TIME_CHECK_WINDOW_START) && ((*gpgga_msg).ss < RTC_TIME_CHECK_WINDOW_END))
//    {
//    rtc_sec = (((*gpgga_msg).rtc_msg[0]>>4)*10) + ((*gpgga_msg).rtc_msg[0]&0x0F);
//    if (((rtc_sec > (*gpgga_msg).ss) && ((rtc_sec - (*gpgga_msg).ss) > RTC_TIME_CHECK_MAX_DIFF)) || ((rtc_sec < (*gpgga_msg).ss) && (((*gpgga_msg).ss - rtc_sec) > RTC_TIME_CHECK_MAX_DIFF)))
//        {
//        (*gpgga_msg).rtc_msg[0] = (*gpgga_msg).xss + 1; // first byte of GPGGA comes 550 ms after 1 PPS strobe
//        (*gpgga_msg).rtc_msg[1] = (*gpgga_msg).xmm;
//        (*gpgga_msg).rtc_msg[2] = (*gpgga_msg).xhh;
//        
//        if (mode&0x01)
//            {
//            reset_time_message();
//            }
//        
//        rtc_alert();
//        rtc_write((*gpgga_msg).rtc_msg, 1);
//        }
//    }    
}